package pri.zxx.learndemo.threademo.base;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class BlockQueueTest<E> implements IBlockQueue<E> {

	private final E[] items;
	private int size;
	private int head;
	private int tail;
	private final ReentrantLock lock = new ReentrantLock();
	private final Condition headWaits = lock.newCondition();
	private final Condition tailWaits = lock.newCondition();


	public BlockQueueTest(int capcity) {
		this.head = 0;
		this.tail = 0;
		this.size = 0;
		items = (E[]) new Object[capcity];
	}

	@Override
	public void offer(E o) throws InterruptedException {
		lock.lockInterruptibly();
		try {
			while (isFull()) {
				tailWaits.await();
			}
			items[tail] = o;
			if (++tail == items.length) {
				tail = 0;
			}
			size++;
			headWaits.signal();
		} finally {
			lock.unlock();
		}
	}

	@Override
	public Boolean offer(E e, long timeOut) throws InterruptedException {
		lock.lockInterruptibly();
		try {
			long l1 = TimeUnit.MILLISECONDS.toNanos(timeOut);
			while (isFull()) {
				if (l1 <= 0) {
					return false;
				}
				l1 = tailWaits.awaitNanos(l1);
			}
			items[tail] = e;
			if (++tail == items.length) {
				tail = 0;
			}
			size++;
			headWaits.signal();
			return true;
		} finally {
			lock.unlock();
		}
	}

	@Override
	public E poll() throws InterruptedException {
		lock.lockInterruptibly();
		try {
			while (isEmpty()) {
				headWaits.wait();
			}
			E item = items[head];
			if (++head == items.length) {
				head = 0;
			}
			size--;
			return item;
		} finally {
			lock.unlock();
		}
	}

	@Override
	public boolean isFull() {
		return size == items.length;
	}

	@Override
	public boolean isEmpty() {
		return size == 0;
	}
}
